package com.surfilter.phantomjs.manage;

import com.surfilter.exception.OprateException;
import com.surfilter.phantomjs.job.KillServer;
import org.openqa.selenium.phantomjs.PhantomJSDriver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * Driver使用完之后必须归还,否则会资源泄露,最终导致没有可用的Driver
 *
 * @author root / grom
 *
 */
public class PhantomJSDriverPools {

    private static final Logger logger = LoggerFactory.getLogger(PhantomJSDriverPools.class);

    private static List<PhantomJSDriverManager> drivers = new ArrayList<>();

    private static PhantomJSDriverPools pools = new PhantomJSDriverPools();

    private static Long time_out = 1 * 1 * 60l;

    private static ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();

    private static ScheduledExecutorService scheduledService = Executors.newSingleThreadScheduledExecutor();

    private static Integer maxPoolSize;

    public static Integer getMaxPoolSize() {
        return maxPoolSize;
    }

    public static void setMaxPoolSize(Integer maxPoolSize) {
        PhantomJSDriverPools.maxPoolSize = maxPoolSize;
    }

    static{
        //初始化排查程序
//        PhantomjsScheduledService scheduledService = new PhantomjsScheduledService();
//        scheduledService.setDrivers(drivers);
//        scheduledService.schedulePhantomjs();
//        logger.info("drivers的地址：,{}",drivers.toString());
//        Runnable runnable = new Runnable() {
//            public void run() {
//                // task to run goes here
//                system_pools_info();
////                clearPhantomJSDrivers(time_out * 500);
////                clearPhantomJSDriversByPort(time_out * 500);
//            }
//        };
//        service.scheduleAtFixedRate(runnable, 10, time_out, TimeUnit.SECONDS);


        /**
         * grom
         * scheduledService
         * Dis:增加调度进程，根据phantomjs的通信端口，杀死phantomjs进程，释放对应Driver
         */
        Runnable scheduledRunnable = new Runnable() {
            public void run() {
                system_pools_info();
                synchronized (drivers) {
                    if(null != drivers && drivers.size() > 0){
                        Iterator<PhantomJSDriverManager> it = drivers.iterator();
                        while(it.hasNext()){
                            PhantomJSDriverManager driver = it.next();
                            Integer port = driver.getPort();
                            logger.info("drivers的port,{}",port);
                            boolean flag = true;
                            // TODO: 2018/1/30 判断phantomjs状态是否僵死
                            if(flag){
                                try {
                                    Thread.sleep(10000);
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                                new KillServer(port).kill();
                                it.remove();
                            }
                        }
                    }
                    logger.info("清理后的driver数量：{}",drivers.size());
                    supplyNewPhantomjs();
                }
            }
        };
        scheduledService.scheduleAtFixedRate(scheduledRunnable, 20, time_out, TimeUnit.SECONDS);
    }

    public static PhantomJSDriverPools single(){
        return pools;
    }

    public static void initDriverPools(int pool_length){
        if(pool_length <= 0)pool_length = 1;
        logger.info("开始初始化PhontomJs线程池,初始化个数：{}", pool_length);
        synchronized (drivers) {
            if(drivers.size() < pool_length){
                createPhantomJSDriver(pool_length - drivers.size());
            }
        }
        logger.info("初始化PhontomJs线程池完成,初始化可用个数：{}", drivers.size());
    }

    /**
     * Grom
     * initDriverPoolsByPort
     * Dis:携带端口初始化phantomjs池
     * @param pool_length
     */
    public static void initDriverPoolsByPort(int pool_length){
        setMaxPoolSize(pool_length);
        if(pool_length <= 0)pool_length = 1;
        logger.info("开始初始化PhontomJs线程池,初始化个数：{}", pool_length);
        synchronized (drivers) {
            if(drivers.size() < pool_length){
                createPhantomJSDriverByPort(pool_length - drivers.size());
            }
        }
        logger.info("初始化PhontomJs线程池完成,初始化可用个数：{}", drivers.size());
    }

    public static PhantomJSDriver getPhantomJSDriver() throws OprateException {
        PhantomJSDriver result = null;
        if(drivers == null){
            throw new OprateException("请先初始化线程池");
        }
        synchronized (drivers) {
            Collections.sort(drivers);
            for(PhantomJSDriverManager driver : drivers){
                if(!driver.isUse()){
                    result = driver.getDriver();
                    driver.setUse(true);
                    driver.setUseTime(System.currentTimeMillis());
                    driver.increasUseNum();
                    break;
                }
            }
        }
        return result;
    }

    public static PhantomJSDriver getPhantomJSDriver(Long time_out) throws OprateException, InterruptedException{
        PhantomJSDriver result = null;
        Long start = System.currentTimeMillis();
        Long end = start;
        while(end - start < time_out){
            result = getPhantomJSDriver();
            if(result != null)break;
            Thread.sleep(3000);
            end = System.currentTimeMillis();
        }
        return result;
    }

    public static PhantomJSDriver getPhantomJSDriverByDefaultTime() throws OprateException, InterruptedException{
        PhantomJSDriver result = getPhantomJSDriver();
        return result;
    }

    public static void reopenPhantomJSDriver(PhantomJSDriver driver){
        if(driver == null){
            return;
        }
        String session = driver.getSessionId().toString();
        synchronized (drivers) {
            for(PhantomJSDriverManager driver_r : drivers){
                if(driver_r.getSessionId().equalsIgnoreCase(session)){
                    driver_r.reopenDriver();
                }
            }
        }
    }

    public static void returnPhantomJSDriver(PhantomJSDriver driver) throws OprateException{
        if(driver == null){
            throw new OprateException("请提供有效参数");
        }
        String session = driver.getSessionId().toString();
        synchronized (drivers) {
            for(PhantomJSDriverManager driver_r : drivers){
                if(driver_r.getSessionId().equalsIgnoreCase(session)){
                    driver_r.needReopen(20);
                    driver_r.setUse(false);
                    driver_r.score();
                }
            }
        }
    }

    private static void clearPhantomJSDrivers(Long time_out){
        if(drivers == null || drivers.size() == 0)return;
        Long this_time = System.currentTimeMillis();
        synchronized (drivers) {
            for(PhantomJSDriverManager driver_r : drivers){
                if(driver_r.isUse()){
                    if(this_time - driver_r.getUseTime() > time_out){
                        driver_r.reopenDriver();
                        driver_r.setUse(false);
                    }
                }
            }
        }
    }

    private static void clearPhantomJSDriversByPort(Long time_out){
        if(drivers == null || drivers.size() == 0)return;
        Long this_time = System.currentTimeMillis();
        synchronized (drivers) {
            logger.info("【clearPhantomJSDriversByPort】-池子当前大小：{}",drivers.size());
            for(PhantomJSDriverManager driver_r : drivers){
                if(driver_r.isUse()){
                    if(this_time - driver_r.getUseTime() > time_out){
                        driver_r.reopenDriver();
                        driver_r.setUse(false);
                    }
                }
            }
        }
    }

    private static void system_pools_info(){
        int pools_size = 0;
        int pools_using = 0;
        synchronized (drivers) {
            pools_size = drivers.size();
                for(PhantomJSDriverManager driver : drivers){
                if(driver.isUse())pools_using ++;
            }
        }
        logger.info("【phantomjs池状态监控】-pools_size:{},pools_using:{}", pools_size, pools_using);
    }

    private static void createPhantomJSDriver(int create_num){
        for(int i = 0 ; i < create_num; i ++){
            PhantomJSDriverManager driverM = new PhantomJSDriverManager();
            driverM.reopenDriver();
            drivers.add(driverM);
        }
    }

    /**
     * grom
     * createPhantomJSDriverByPort
     * Dis：获取通信端口获取phantomjs
     * @param create_num
     */
    private static void createPhantomJSDriverByPort(int create_num){
        for(int i = 0 ; i < create_num; i ++){
            PhantomJSDriverManager driverM = new PhantomJSDriverManager();
            driverM.reopenDriverByPort();
            drivers.add(driverM);
        }
    }

    private PhantomJSDriverPools(){}

    public static void main(String[] args) {
        try{
            throw new org.openqa.selenium.remote.UnreachableBrowserException("");
        }catch(Exception e){

        }finally{
            System.out.println("123123123");
        }
    }

    /**
     * Grom
     * supplyNewPhantomjs
     * Dis:杀死phantomjs进程和driver后，需要补给phantomjs池
     */
    public static void supplyNewPhantomjs() {
        if(drivers.size() < maxPoolSize){
            logger.info("【phantomjs补全程序】-当前池中数量：{},池子最大数量：{}",drivers.size(),maxPoolSize);
            createPhantomJSDriverByPort(maxPoolSize - drivers.size());
        }
    }
}
